// 2014年版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

package types2

import (
	"cmd/compile/internal/syntax"
	"fmt"
	"go/constant"
)

func (err *error_) recordAltDecl(obj Object) {
	if pos := obj.Pos(); pos.IsKnown() {
		// 我们在这里使用“其他”而不是“先前”，因为
		// 看到的第一个声明可能不是文本
		// 在源代码的前面。
		err.errorf(pos, "other declaration of %s", obj.Name())
	}
}

func (check *Checker) declare(scope *Scope, id *syntax.Name, obj Object, pos syntax.Pos) {
	// spec:“空白标识符，用下划线表示
	// 字符u，可以像任何其他字符一样在声明中使用
	// 标识符，但声明不引入新的
	// 绑定。”
	if obj.Name() != "_" {
		if alt := scope.Insert(obj); alt != nil {
			var err error_
			err.errorf(obj, "%s redeclared in this block", obj.Name())
			err.recordAltDecl(alt)
			check.report(&err)
			return
		}
		obj.setScopePos(pos)
	}
	if id != nil {
		check.recordDef(id, obj)
	}
}

// pathString返回格式为a->b->…->的字符串g表示路径[a，b，…g]。
func pathString(path []Object) string {
	var s string
	for i, p := range path {
		if i > 0 {
			s += "->"
		}
		s += p.Name()
	}
	return s
}

// objDecl类型检查obj在其各自（文件）上下文中的声明。
// 有关def的含义，请参阅typexpr.go中的Checker.definedType。
func (check *Checker) objDecl(obj Object, def *Named) {
	if check.conf.Trace && obj.Type() == nil {
		if check.indent == 0 {
			fmt.Println() // 顶层对象之间的空行以提高可读性
		}
		check.trace(obj.Pos(), "-- checking %s (%s, objPath = %s)", obj, obj.color(), pathString(check.objPath))
		check.indent++
		defer func() {
			check.indent--
			check.trace(obj.Pos(), "=> %s (%s)", obj, obj.color())
		}()
	}

	// 检查obj的声明意味着推断其类型
	// （对于常数，可能还有其值）。
	// 对象的类型（以及对象）可以是以下类型之一：
	// 以颜色表示的三种状态：
	// None
	// -类型未知的对象被绘制为白色（初始颜色）
	// -正在推断其类型的对象被涂成灰色
	// -完全推断其类型的对象被绘制为黑色
	// None
	// 在类型推断过程中，对象的颜色从白色变为灰色
	// 变为黑色（预先声明的对象从一开始就被绘制为黑色）。
	// 黑色对象（即其类型）只能依赖于（参考）其他黑色对象
	// 一个。白色和灰色对象可能依赖于白色和黑色对象。
	// 对灰色对象的依赖性表示一个循环，该循环可能是，也可能不是
	// 有效的
	// None
	// 当对象变成灰色时，它们被推到对象路径（堆栈）上；
	// 当它们变黑时，会再次弹出。因此，如果灰色对象（a
	// 循环），它位于对象路径上，并且所有对象
	// 这取决于该路径上的剩余对象。颜色编码
	// 是指灰色对象的颜色值指示
	// 对象路径中的该对象。

	// 在类型检查期间，可以为白色对象指定一个类型，而不指定
	// 通过objDecl进行遍历；e、 例如，初始化常量和
	// 变量。在此处更新这些对象的颜色（而不是
	// 我们设置类型的地方）以满足颜色不变量。
	if obj.color() == white && obj.Type() != nil {
		obj.setColor(black)
		return
	}

	switch obj.color() {
	case white:
		assert(obj.Type() == nil)
		// 除白色和黑色以外的所有颜色值均视为灰色。
		// 因为黑色和白色是<灰色的，所以所有>=灰色的值都是灰色的。
		// 使用这些值将对象的索引编码到对象路径中。
		obj.setColor(grey + color(check.push(obj)))
		defer func() {
			check.pop().setColor(black)
		}()

	case black:
		assert(obj.Type() != nil)
		return

	default:
		// 除白色或黑色以外的颜色值被视为灰色。
		fallthrough

	case grey:
		// 我们有一个循环。
		// 在现有代码中，这是由非nil类型标记的
		// 用于对象，但常数和变量除外
		// 类型可以是非nil（已知），或nil（如果它取决于
		// 尚未知道初始化值。
		// 在前一种情况下，将类型设置为Typ[Invalid]，因为
		// 我们有一个初始化周期。循环误差将被忽略
		// 稍后在确定初始化顺序时报告。
		// TODO（gri）报告在此循环并简化初始化
		// 订单代码。
		switch obj := obj.(type) {
		case *Const:
			if check.cycle(obj) || obj.typ == nil {
				obj.typ = Typ[Invalid]
			}

		case *Var:
			if check.cycle(obj) || obj.typ == nil {
				obj.typ = Typ[Invalid]
			}

		case *TypeName:
			if check.cycle(obj) {
				// 中断周期
				// （如果没有此选项，则调用底层（）
				// 下面可能会导致一个无休止的循环
				// 如果我们有一个定义的循环
				// （*命名）类型）
				obj.typ = Typ[Invalid]
			}

		case *Func:
			if check.cycle(obj) {
				// 此处不要将obj.typ设置为typ[Invalid]
				// 因为很多代码类型都断言这一点
				// 函数具有*签名类型。灰色
				// 函数的类型设置为空
				// 签名使其无法
				// 使用函数初始化变量。
			}

		default:
			unreachable()
		}
		assert(obj.Type() != nil)
		return
	}

	d := check.objMap[obj]
	if d == nil {
		check.dump("%v: %s should have been declared", obj.Pos(), obj)
		unreachable()
	}

	// 保存/还原当前上下文和设置对象上下文
	defer func(ctxt context) {
		check.context = ctxt
	}(check.context)
	check.context = context{
		scope: d.file,
	}

	// Const和var声明不能有初始化
	// 周期。我们通过记住当前的声明来跟踪它们
	// 在检查中。初始化表达式取决于其他
	// 常量、变量或函数将依赖项添加到当前
	// 查一查。
	switch obj := obj.(type) {
	case *Const:
		check.decl = d // 新包级别常量decl
		check.constDecl(obj, d.vtyp, d.init, d.inherited)
	case *Var:
		check.decl = d // 新的包级别var decl
		check.varDecl(obj, d.lhs, d.vtyp, d.init)
	case *TypeName:
		// 通过路径检测到无效的递归类型
		check.typeDecl(obj, d.tdecl, def)
		check.collectMethods(obj) // 方法只能添加到顶级类型
	case *Func:
		// 函数可能是递归的-无需跟踪依赖项
		check.funcDecl(obj, d)
	default:
		unreachable()
	}
}

// 循环检查以obj开始的循环是否有效，以及
// 如果不是，则报告错误。
func (check *Checker) cycle(obj Object) (isCycle bool) {
	// 对象映射包含包范围对象和非接口方法。
	if debug {
		info := check.objMap[obj]
		inObjMap := info != nil && (info.fdecl == nil || info.fdecl.Recv == nil) // 排除方法
		isPkgObj := obj.Parent() == check.pkg.scope
		if isPkgObj != inObjMap {
			check.dump("%v: inconsistent object map for %s (isPkgObj = %v, inObjMap = %v)", obj.Pos(), obj, isPkgObj, inObjMap)
			unreachable()
		}
	}

	// 计数循环对象。
	assert(obj.color() >= grey)
	start := obj.color() - grey // objPath中obj的索引
	cycle := check.objPath[start:]
	nval := 0 // 循环中的（常量或变量）值数
	ndef := 0 // 循环中的类型定义数
	for _, obj := range cycle {
		switch obj := obj.(type) {
		case *Const, *Var:
			nval++
		case *TypeName:
			// 确定类型名称是否为别名。对于
			// 包级别对象，使用
			// 提供语法信息（不依赖于
			// 根据对象的设置顺序）。对于
			// 局部对象，我们可以依赖顺序，所以使用
			// 对象的谓词。
			// TODO（gri）始终访问将不那么脆弱
			// 句法信息。我们应该考虑储存。
			// 此信息在对象中显式显示。
			var alias bool
			if d := check.objMap[obj]; d != nil {
				alias = d.tdecl.Alias // 包级对象
			} else {
				alias = obj.IsAlias() // 函数局部对象
			}
			if !alias {
				ndef++
			}
		case *Func:
			// 暂时忽略
		default:
			unreachable()
		}
	}

	if check.conf.Trace {
		check.trace(obj.Pos(), "## cycle detected: objPath = %s->%s (len = %d)", pathString(cycle), obj.Name(), len(cycle))
		check.trace(obj.Pos(), "## cycle contains: %d values, %d type definitions", nval, ndef)
		defer func() {
			if isCycle {
				check.trace(obj.Pos(), "=> error: cycle is invalid")
			}
		}()
	}

	// 只涉及常量和变量的循环是无效的，但我们
	// 在此处忽略它们，因为它们是通过初始化报告的
	// 循环检查。
	if nval == len(cycle) {
		return false
	}

	// 仅涉及类型（可能还有函数）的循环必须至少具有
	// 允许一个类型定义：如果没有类型定义，我们
	// 具有将无限扩展的别名类型名称序列。
	if nval == 0 && ndef > 0 {
		return false // 循环是允许的
	}

	check.cycleError(cycle)

	return true
}

type typeInfo uint

// validType验证给定类型不会无限“扩展”
// 在类型图中生成循环。通过标记来检测循环
// 定义的类型。
// （检测到涉及别名类型的循环，如“类型A=[10]A”中的循环）
// 之前，通过objDecl循环检测机制。）
func (check *Checker) validType(typ Type, path []Object) typeInfo {
	const (
		unknown typeInfo = iota
		marked
		valid
		invalid
	)

	switch t := typ.(type) {
	case *Array:
		return check.validType(t.elem, path)

	case *Struct:
		for _, f := range t.fields {
			if check.validType(f.typ, path) == invalid {
				return invalid
			}
		}

	case *Interface:
		for _, etyp := range t.embeddeds {
			if check.validType(etyp, path) == invalid {
				return invalid
			}
		}

	case *Named:
		// 如果类型来自不同的软件包或宇宙范围，请不要触摸该类型
		// （这样做会导致比赛状态-was问题#35049）
		if t.obj.pkg != check.pkg {
			return valid
		}

		// 如果我们已经知道类型无效，请不要报告第二个错误
		// （例如，如果更早检测到循环，则通过欠压）。
		if t.underlying == Typ[Invalid] {
			t.info = invalid
			return invalid
		}

		switch t.info {
		case unknown:
			t.info = marked
			t.info = check.validType(t.fromRHS, append(path, t.obj)) // 仅将当前包的类型添加到路径
		case marked:
			// 检测到的周期
			for i, tn := range path {
				if t.obj.pkg != check.pkg {
					panic("internal error: type cycle via package-external type")
				}
				if tn == t.obj {
					check.cycleError(path[i:])
					t.info = invalid
					return t.info
				}
			}
			panic("internal error: cycle start not found")
		}
		return t.info

	case *instance:
		return check.validType(t.expand(), path)
	}

	return valid
}

// cycleError报告一个以
// 循环中源中“第一个”的对象。
func (check *Checker) cycleError(cycle []Object) {
	// TODO（gri）我们应该从循环中的最后一个（而不是第一个）对象开始吗
	// 因为那是我们在源头上最早看到
	// 周期这将与其他错误消息更加一致。
	i := firstInSrc(cycle)
	obj := cycle[i]
	var err error_
	if check.conf.CompilerErrorMessages {
		err.errorf(obj, "invalid recursive type %s", obj.Name())
	} else {
		err.errorf(obj, "illegal cycle in declaration of %s", obj.Name())
	}
	for range cycle {
		err.errorf(obj, "%s refers to", obj.Name())
		i++
		if i >= len(cycle) {
			i = 0
		}
		obj = cycle[i]
	}
	err.errorf(obj, "%s", obj.Name())
	check.report(&err)
}

// firstInSrc报告具有“最小值”的对象的索引
// 源在路径中的位置。路径不能为空。
func firstInSrc(path []Object) int {
	fst, pos := 0, path[0].Pos()
	for i, t := range path[1:] {
		if t.Pos().Cmp(pos) < 0 {
			fst, pos = i+1, t.Pos()
		}
	}
	return fst
}

func (check *Checker) constDecl(obj *Const, typ, init syntax.Expr, inherited bool) {
	assert(obj.typ == nil)

	// 使用iota和errpos的正确值
	defer func(iota constant.Value, errpos syntax.Pos) {
		check.iota = iota
		check.errpos = errpos
	}(check.iota, check.errpos)
	check.iota = obj.val
	check.errpos = nopos

	// 在所有情况下提供有效的常量值
	obj.val = constant.MakeUnknown()

	// 确定类型（如有）
	if typ != nil {
		t := check.typ(typ)
		if !isConstType(t) {
			// 如果类型是无效的C（已定义）类型，则不要报告错误
			// （第22090期）
			if under(t) != Typ[Invalid] {
				check.errorf(typ, "invalid constant type %s", t)
			}
			obj.typ = Typ[Invalid]
			return
		}
		obj.typ = t
	}

	// 检查初始化
	var x operand
	if init != nil {
		if inherited {
			// 初始化表达式继承自上一个表达式
			// 常量声明和（错误）位置指的是
			// 表达式，而不是当前常量声明。使用
			// 过程中任何错误的常量标识符位置
			// 初始化表达式求值，因为这是我们的全部
			// （见第42991期和第42992期）。
			check.errpos = obj.pos
		}
		check.expr(&x, init)
	}
	check.initConst(obj, &x)
}

func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init syntax.Expr) {
	assert(obj.typ == nil)

	// 如果由于错误导致变量类型未定义，
	// 将变量标记为用于避免后续错误。
	// 匹配编译器行为。
	defer func() {
		if obj.typ == Typ[Invalid] {
			obj.used = true
		}
		for _, lhs := range lhs {
			if lhs.typ == Typ[Invalid] {
				lhs.used = true
			}
		}
	}()

	// 确定类型（如有）
	if typ != nil {
		obj.typ = check.varType(typ)
		// 如果存在以下情况，我们无法将该类型扩展到所有lhs变量
		// 不止一个，因为这会将它们标记为已检查
		// （参见Checker.objDecl）和init expr的赋值，
		// 如果有，将不进行检查。
		// None
		// TODO（gri）如果我们没有init expr，我们应该分发
		// 一个给定的类型，否则我们需要重新计算该类型
		// 每个lhs变量的expr，导致重复工作。
	}

	// 检查初始化
	if init == nil {
		if typ == nil {
			// arityMatch之前报告的错误
			obj.typ = Typ[Invalid]
		}
		return
	}

	if lhs == nil || len(lhs) == 1 {
		assert(lhs == nil || lhs[0] == obj)
		var x operand
		check.expr(&x, init)
		check.initVar(obj, &x, "variable declaration")
		return
	}

	if debug {
		// obj必须是lhs之一
		found := false
		for _, lhs := range lhs {
			if obj == lhs {
				found = true
				break
			}
		}
		if !found {
			panic("inconsistent lhs")
		}
	}

	// 我们在lhs上有多个变量和一个init expr。
	// 如果需要，请确保所有变量的类型都相同
	// 指定了一个，否则它们将假定
	// 初始表达式值（问题#15755）。
	if typ != nil {
		for _, lhs := range lhs {
			lhs.typ = obj.typ
		}
	}

	check.initVars(lhs, []syntax.Expr{init}, nopos)
}

// under返回n0的扩展基础类型；可能通过以下方式
// 命名类型的前向链。如果找到基础类型，请解析
// 通过为中定义的每个类型设置基础类型来创建链
// 在归还之前先把链条锁上。如果未找到基础类型或循环
// 如果检测到，则结果为Typ[无效]。如果检测到一个循环，并且
// 不，检查！=无，循环已报告。
func (n0 *Named) under() Type {
	u := n0.underlying
	if u == nil {
		return Typ[Invalid]
	}

	// 如果已定义类型的基础类型不是已定义的
	// 类型，则该类型是所需的基础类型。
	n := asNamed(u)
	if n == nil {
		return u // 常见情况
	}

	// 否则，请遵循前进链。
	seen := map[*Named]int{n0: 0}
	path := []Object{n0.obj}
	for {
		u = n.underlying
		if u == nil {
			u = Typ[Invalid]
			break
		}
		n1 := asNamed(u)
		if n1 == nil {
			break // 链的末端
		}

		seen[n] = len(seen)
		path = append(path, n.obj)
		n = n1

		if i, ok := seen[n]; ok {
			// 周期
			// TODO（gri）将其还原为检查器上的方法。有可能
			// Named和TypeParam上的nil Checker太微妙了。
			if n0.check != nil {
				n0.check.cycleError(path[i:])
			}
			u = Typ[Invalid]
			break
		}
	}

	for n := range seen {
		// 我们永远不必更新导入类型的基础类型；
		// 这些基础类型应该在导入期间已解析。
		// 此外，这样做会导致比赛状态（was问题31749）。
		// 始终执行此检查，而不仅仅是调试更多（这很便宜）。
		if n0.check != nil && n.obj.pkg != n0.check.pkg {
			panic("internal error: imported type with unresolved underlying type")
		}
		n.underlying = u
	}

	return u
}

func (n *Named) setUnderlying(typ Type) {
	if n != nil {
		n.underlying = typ
	}
}

func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named) {
	assert(obj.typ == nil)

	check.later(func() {
		check.validType(obj.typ, nil)
	})

	alias := tdecl.Alias
	if alias && tdecl.TParamList != nil {
		// 解析器将确保这一点，但我们仍然可能得到一个无效的AST。
		// 投诉并继续作为常规类型定义。
		check.error(tdecl, "generic type cannot be alias")
		alias = false
	}

	if alias {
		// 类型别名声明
		if !check.allowVersion(check.pkg, 1, 9) {
			if check.conf.CompilerErrorMessages {
				check.error(tdecl, "type aliases only supported as of -lang=go1.9")
			} else {
				check.error(tdecl, "type aliases requires go1.9 or later")
			}
		}

		obj.typ = Typ[Invalid]
		obj.typ = check.anyType(tdecl.Type)

	} else {
		// 定义类型声明

		named := check.newNamed(obj, nil, nil, nil, nil)
		def.setUnderlying(named)

		if tdecl.TParamList != nil {
			check.openScope(tdecl, "type parameters")
			defer check.closeScope()
			named.tparams = check.collectTypeParams(tdecl.TParamList)
		}

		// 确定命名对象的基础类型
		named.fromRHS = check.definedType(tdecl.Type, named)

		// 命名的基础类型本身可能是
		// 不完整：
		// None
		// 类型(
		// A B
		// B*C
		// C A
		// )
		// None
		// C的类型是不完整的A的（命名）类型，
		// 其基础类型为命名类型B。
		// 通过解析确定（最终的、未命名的）基础类型
		// 任何前链。
		// TODO（gri）调查是否可以在此处使用named.fromRHS
		// 并且依赖于底层类型的延迟计算。
		named.underlying = under(named)
	}

}

func (check *Checker) collectTypeParams(list []*syntax.Field) (tparams []*TypeName) {
	// 类型参数列表不应为空。解析器将
	// 抱怨，但我们仍然可能得到错误的AST：忽略它。
	if len(list) == 0 {
		return
	}

	// 预先声明类型参数，将空接口作为类型绑定。
	// 类型参数的范围从类型参数的开头开始
	// 列表（这样我们就可以拥有相互递归的参数化接口）。
	for _, f := range list {
		tparams = check.declareTypeParam(tparams, f.Name)
	}

	var bound Type
	for i, j := 0, 0; i < len(list); i = j {
		f := list[i]

		// 确定具有相同类型边界的类型参数列表[i:j]的范围
		// （声明为（a、b、c、b类））
		j = i + 1
		for j < len(list) && list[j].Type == f.Type {
			j++
		}

		// 这种情况永远不应该发生，但要小心
		if f.Type == nil {
			continue
		}

		// 预先声明的标识符“any”仅作为约束可见
		// 在类型参数列表中。在常规约束之前查找它
		// 决议
		if tident, _ := unparen(f.Type).(*syntax.Name); tident != nil && tident.Value == "any" && check.lookup("any") == nil {
			bound = universeAny
		} else {
			bound = check.typ(f.Type)
		}

		// 类型绑定必须是接口
		// TODO（gri）我们应该延迟接口检查，因为
		// 我们可能还没有一个完整的界面：
		// 类型C（类型TC）接口{}
		// （第39724期）。
		if _, ok := under(bound).(*Interface); ok {
			// 设置类型边界
			for i < j {
				tparams[i].typ.(*TypeParam).bound = bound
				i++
			}
		} else if bound != Typ[Invalid] {
			check.errorf(f.Type, "%s is not an interface", bound)
		}
	}

	return
}

func (check *Checker) declareTypeParam(tparams []*TypeName, name *syntax.Name) []*TypeName {
	tpar := NewTypeName(name.Pos(), check.pkg, name.Value, nil)
	check.NewTypeParam(tpar, len(tparams), &emptyInterface) // 将类型指定给tpar作为副作用
	check.declare(check.scope, name, tpar, check.scope.pos) // TODO（gri）检查范围位置
	tparams = append(tparams, tpar)

	if check.conf.Trace {
		check.trace(name.Pos(), "type param = %v", tparams[len(tparams)-1])
	}

	return tparams
}

func (check *Checker) collectMethods(obj *TypeName) {
	// 获取关联的方法
	// （Checker.collectObjects仅收集具有非空名称的方法；
	// Checker.resolveBaseTypeName确保obj不是别名
	// 如果它有附加的方法。）
	methods := check.methods[obj]
	if methods == nil {
		return
	}
	delete(check.methods, obj)
	assert(!check.objMap[obj].tdecl.Alias) // 不要使用TypeName.IsAlias（需要完全设置对象）

	// 使用对象集检查名称冲突
	var mset objset

	// 规范：“如果基类型是结构类型，则非空方法
	// 字段名必须是不同的。”
	base := asNamed(obj.typ) // 不应该失败，但要保守
	if base != nil {
		if t, _ := base.underlying.(*Struct); t != nil {
			for _, fld := range t.fields {
				if fld.name != "_" {
					assert(mset.insert(fld) == nil)
				}
			}
		}

		// Checker.文件可以多次调用；附加程序包文件
		// 可以向已检查的类型添加方法。添加预先存在的方法
		// 这样我们就可以检测到重新声明。
		for _, m := range base.methods {
			assert(m.name != "_")
			assert(mset.insert(m) == nil)
		}
	}

	// 添加有效的方法
	for _, m := range methods {
		// spec:“对于基类型，绑定的方法的非空名称
		// 它必须是独一无二的。”
		assert(m.name != "_")
		if alt := mset.insert(m); alt != nil {
			var err error_
			switch alt.(type) {
			case *Var:
				err.errorf(m.pos, "field and method with the same name %s", m.name)
			case *Func:
				if check.conf.CompilerErrorMessages {
					err.errorf(m.pos, "%s.%s redeclared in this block", obj.Name(), m.name)
				} else {
					err.errorf(m.pos, "method %s already declared for %s", m.name, obj)
				}
			default:
				unreachable()
			}
			err.recordAltDecl(alt)
			check.report(&err)
			continue
		}

		if base != nil {
			base.methods = append(base.methods, m)
		}
	}
}

func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
	assert(obj.typ == nil)

	// func声明不能使用iota
	assert(check.iota == nil)

	sig := new(Signature)
	obj.typ = sig // 提防周期

	// 在类型检查签名时引用方法时避免循环错误。
	// 这在最佳情况下（非参数化接收器类型）避免了麻烦，并且
	// 由于该方法不是一个类型，我们得到一个错误。如果我们有一个参数化的
	// 接收方类型，实例化接收方类型将导致
	// 它的方法，我们不希望在这种情况下出现循环错误。
	// TODO（gri）审查这是否正确和/或我们是否仍然需要？
	saved := obj.color_
	obj.color_ = black
	fdecl := decl.fdecl
	check.funcType(sig, fdecl.Recv, fdecl.TParamList, fdecl.Type)
	obj.color_ = saved

	// 函数体必须在全局声明后进行类型检查
	// （其他地方执行的职能没有主体）
	if !check.conf.IgnoreFuncBodies && fdecl.Body != nil {
		check.later(func() {
			check.funcBody(decl, obj.name, sig, fdecl.Body, nil)
		})
	}
}

func (check *Checker) declStmt(list []syntax.Decl) {
	pkg := check.pkg

	first := -1                // 当前组中第一个ConstDecl的索引，或-1
	var last *syntax.ConstDecl // 带有init表达式的last ConstDecl，或nil
	for index, decl := range list {
		if _, ok := decl.(*syntax.ConstDecl); !ok {
			first = -1 // 我们不是在一个固定的声明中
		}

		switch s := decl.(type) {
		case *syntax.ConstDecl:
			top := len(check.delayed)

			// iota是组内当前constDecl的索引
			if first < 0 || list[index-1].(*syntax.ConstDecl).Group != s.Group {
				first = index
				last = nil
			}
			iota := constant.MakeInt64(int64(index - first))

			// 确定要使用的初始化表达式
			inherited := true
			switch {
			case s.Type != nil || s.Values != nil:
				last = s
				inherited = false
			case last == nil:
				last = new(syntax.ConstDecl) // 确保最后一个存在
				inherited = false
			}

			// 声明所有常量
			lhs := make([]*Const, len(s.NameList))
			values := unpackExpr(last.Values)
			for i, name := range s.NameList {
				obj := NewConst(name.Pos(), pkg, name.Value, nil, iota)
				lhs[i] = obj

				var init syntax.Expr
				if i < len(values) {
					init = values[i]
				}

				check.constDecl(obj, last.Type, init, inherited)
			}

			// 常量必须始终具有初始值。
			check.arity(s.Pos(), s.NameList, values, true, inherited)

			// 在范围更改之前处理init表达式中的函数文本
			check.processDelayed(top)

			// spec：“声明的常量或变量标识符的范围
			// 函数内部从ConstSpec或VarSpec的末尾开始
			// （ShortVarDecl表示短变量声明）并在
			// 最里面的包含块的结尾。“
			scopePos := syntax.EndPos(s)
			for i, name := range s.NameList {
				check.declare(check.scope, name, lhs[i], scopePos)
			}

		case *syntax.VarDecl:
			top := len(check.delayed)

			lhs0 := make([]*Var, len(s.NameList))
			for i, name := range s.NameList {
				lhs0[i] = NewVar(name.Pos(), pkg, name.Value, nil)
			}

			// 初始化所有变量
			values := unpackExpr(s.Values)
			for i, obj := range lhs0 {
				var lhs []*Var
				var init syntax.Expr
				switch len(values) {
				case len(s.NameList):
					// 左、右匹配
					init = values[i]
				case 1:
					// rhs应该是一个多值表达式
					lhs = lhs0
					init = values[0]
				default:
					if i < len(values) {
						init = values[i]
					}
				}
				check.varDecl(obj, lhs, s.Type, init)
				if len(values) == 1 {
					// 如果我们只有一个lhs变量，那么我们可以采用任何一种方法。
					// 如果我们有一个rhs表达式，那么它必须是一个多重表达式-
					// 值表达式，在这种情况下处理第一个lhs
					// 变量将使所有lhs变量具有一个类型
					// 分配，我们也完成了。
					if debug {
						for _, obj := range lhs0 {
							assert(obj.typ != nil)
						}
					}
					break
				}
			}

			// 如果没有类型，就必须有值。
			if s.Type == nil || values != nil {
				check.arity(s.Pos(), s.NameList, values, false, false)
			}

			// 在范围更改之前处理init表达式中的函数文本
			check.processDelayed(top)

			// 声明所有变量
			// （只有在这一点上才设置了变量作用域（父项）
			scopePos := syntax.EndPos(s) // 参见常量声明
			for i, name := range s.NameList {
				// 参见常量声明
				check.declare(check.scope, name, lhs0[i], scopePos)
			}

		case *syntax.TypeDecl:
			obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Value, nil)
			// spec:“在函数中声明的类型标识符的范围
			// 从TypeSpec中的标识符开始，到
			// 最里面的包含块。”
			scopePos := s.Name.Pos()
			check.declare(check.scope, s.Name, obj, scopePos)
			// 在调用typeDecl之前标记和取消标记type；其类型仍然为nil（请参见Checker.objDecl）
			obj.setColor(grey + color(check.push(obj)))
			check.typeDecl(obj, s, nil)
			check.pop().setColor(black)

		default:
			check.errorf(s, invalidAST+"unknown syntax.Decl node %T", s)
		}
	}
}
